package com.teach.service.impl;

import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import java.util.Random;

import javax.imageio.ImageIO;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.teach.commons.Id;
import com.teach.config.ConfigProperties;
import com.teach.exception.CodeException;
import com.teach.service.FileService;
import com.teach.service.HttpService;
import com.teach.service.WatermarkService;
import com.teach.service.http.Request;
import com.teach.service.http.Request.Method;

import lombok.extern.slf4j.Slf4j;
import net.coobird.thumbnailator.Thumbnails;
import net.coobird.thumbnailator.geometry.Positions;

/**
 * <pre>
 * 文件服务基于Go-FastDFS的实现
 * 相关配置：config.go-fast-dfs
 * 默认服务器：server:http://files.jlzhou.top/group1/upload
 * 默认场景：scene:student
 * 默认token：token:1qaz!QAZ
 * 暂未实现
 * 创建时间 ：	2019年12月10日 上午11:51:43
 * 当前版本 ：	V1.0
 * Copyright © 1998 - 2019 jlzhou.top. All Rights Reserved
 * </pre>
 * 
 * @author J.L.Zhou
 *
 */
@Service
@Slf4j
public class FileServiceImplByGoFastDFS implements FileService {

	@Autowired
	private WatermarkService watermarkService;

	@Autowired
	private ConfigProperties config;

	@Autowired
	private HttpService service;

	@Autowired
	private ObjectMapper mapper;

	@Override
	public String saveImage(MultipartFile file) {
		if (file == null || file.isEmpty()) {
			throw new CodeException(203);
		}

		BufferedImage img = null;
		try {
			img = ImageIO.read(file.getInputStream());
		} catch (Exception e) {
			throw new CodeException(205, e);
		}
		// 如果图片高和宽任意一个大于缩略图限制大小就要缩小

		ByteArrayOutputStream out = null;
		ByteArrayInputStream in = null;
		try {
			out = new ByteArrayOutputStream();
			if (img.getWidth() > config.image.width || img.getHeight() > config.image.height) {
				Thumbnails.of(img).size(config.image.width, config.image.height)
						.watermark(Positions.CENTER, watermarkService.getWatermark(), 1)
						.outputQuality(config.image.quality).outputFormat("JPEG").toOutputStream(out);
			} else {
				Thumbnails.of(img).width(img.getWidth()).watermark(Positions.CENTER, watermarkService.getWatermark(), 1)
						.outputQuality(config.image.quality).outputFormat("JPEG").toOutputStream(out);
			}
			in = new ByteArrayInputStream(out.toByteArray());

		} catch (Exception e) {
			throw new CodeException(206, e);
		} finally {
			try {
				out.close();
				out = null;
			} catch (Exception e) {
				log.warn("关闭图片输出流失败", e);
			}
		}
		return save(in, "image/jpeg", ".jpg", true);
	}

	@Override
	public String saveThumbnail(MultipartFile file) {
		if (file == null || file.isEmpty()) {
			throw new CodeException(203);
		}

		BufferedImage img = null;
		try {
			img = ImageIO.read(file.getInputStream());
		} catch (Exception e) {
			throw new CodeException(205, e);
		}
		// 如果图片高和宽任意一个大于缩略图限制大小就要缩小
		if (img.getWidth() > config.image.thumbnailWidth || img.getHeight() > config.image.thumbnailHeight) {
			ByteArrayOutputStream out = null;
			ByteArrayInputStream in = null;
			try {
				out = new ByteArrayOutputStream();
				Thumbnails.of(img).size(config.image.thumbnailWidth, config.image.thumbnailHeight)
						.outputQuality(config.image.quality).outputFormat("JPEG").toOutputStream(out);
				in = new ByteArrayInputStream(out.toByteArray());
			} catch (Exception e) {
				throw new CodeException(207, e);
			} finally {
				try {
					out.close();
					out = null;
				} catch (Exception e) {
					log.warn("关闭图片输出流失败", e);
				}
			}
			return save(in, "image/jpeg", ".jpg", true);
		} else {
			try {
				return save(file.getInputStream(), file.getContentType(), file.getOriginalFilename(), true);
			} catch (IOException e) {
				throw new CodeException(204, e);
			}
		}
	}

	@Override
	public String save(MultipartFile file, boolean randomNameable) {
		if (file == null || file.isEmpty()) {
			throw new CodeException(203);
		}
		try {
			return save(file.getInputStream(), file.getContentType(), file.getOriginalFilename(), randomNameable);
		} catch (IOException e) {
			throw new CodeException(204, e);
		}
	}

	public String save(InputStream stream, String contentType, String filename, boolean randomNameable) {
		try {
			if (!config.goFastDfs.enable) {
				return "http://files.jlzhou.top/group1/jlzhou/20191210/12/54/6/_noimg.png";
			}
			Request request = new Request(config.goFastDfs.server);
			request.setMethod(Method.POST).addParameter("scene", config.goFastDfs.scene).addParameter("output", "json")
					.addParameter("path", config.goFastDfs.path).addParameter("auth_token", config.goFastDfs.token);
//				.addHeader("Content-Type", "multipart/form-data");

			if (randomNameable) {
				request.addFile("file", stream, contentType,
						Integer.toString(new Random().nextInt(60466176), 36) + getFileExt(filename));
			} else {
				request.addFile("file", stream, contentType, filename);
			}

			String body = "";
			try {
				body = service.send(request);
			} catch (Exception e) {
				log.debug("访问错误", e);
				throw new CodeException(201, e);
			}
			log.debug(body);

			Map<String, String> data = null;
			try {
				JavaType type = mapper.getTypeFactory().constructParametricType(Map.class, String.class, String.class);
				data = mapper.readValue(body, type);
			} catch (Exception e) {
				log.debug("读取结果", e);
				throw new CodeException(202, e);
			}

			return data.get("url");
		} finally {
			try {
				stream.close();
				stream = null;
			} catch (Exception e) {
				log.warn("关闭上传文件输入流失败", e);
			}
		}
	}

	public String getFileExt(String fileName) {
		int index = fileName.lastIndexOf(".");
		if (index == -1) {
			return "";
		} else {
			return fileName.substring(index).toLowerCase();
		}
	}
}
